#include <ftp_util.h>
#include <AsyncLogger.h>
#include <fmt/format.h>
#include <sstream>
#include <chrono>
#include <array>

namespace FTPUtil {

	bool exist(const std::string& filename)
	{
		bool existed = false;
		try {
			existed = std::filesystem::exists(filename);
		}
		catch (const std::filesystem::filesystem_error& error) {
			std::string errMsg = fmt::format("Exist file failed. msg: {}", error.what());
			LOG_ERROR << errMsg;
			return false;
		}
		return existed;
	}

	bool mkdir(const std::string& dirname)
	{
		try {
			std::filesystem::create_directory(dirname);
		}
		catch (const std::filesystem::filesystem_error& err) {
			LOG_ERROR << err.what();
			return false;
		}
		return true;
	}
	bool rmdir(const std::string& dirname)
	{
		try
		{
			std::filesystem::remove_all(dirname);
		}
		catch (const std::filesystem::filesystem_error& err)
		{
			LOG_ERROR << err.what();
			return false;
		}
		return true;
	}

	bool getFileSize(const std::string& filename, size_t& filesize)
	{
		try {
			filesize = std::filesystem::file_size(filename);
		}
		catch (const std::filesystem::filesystem_error& error) {
			std::string errMsg = fmt::format("try to get file size failed. msg: {}", error.what());
			LOG_ERROR << errMsg;
			return false;
		}
		return true;
	}

	bool getFileInfo(const std::string& filename, std::string& info, UserPermission permission)
	{
		info = "";
		// 目录返回当前目录下的文件列表，文件返回名字、大小、修改时间、文件类型
		if (!exist(filename)) {
			return false;
		}
		try {
			// 普通文件
			if (std::filesystem::is_regular_file(filename)) {

				std::string infoEntry;
				bool res = getSingleFileInfo(filename, infoEntry);
				if (res) {
					info = fmt::format("{}\r\n", infoEntry);
				}
			}
			// 目录文件
			else if (std::filesystem::is_directory(filename)) {
				for (const auto& entry : std::filesystem::directory_iterator(filename)) {
					std::string _filename = entry.path().filename().string(); // 获取不带文件夹的文件名
					//if (_filename == "." || _filename == "..") {
					//	continue;
					//}
					std::string infoEntry;
					bool res = getSingleFileInfo(entry.path().string(), infoEntry, permission);
					if (!res) {
						return false;
					}
					info += fmt::format("{}\r\n", infoEntry);
				}
			}
			else {
				LOG_ERROR << "Unknown file type: " << filename;
				return false;
			}
		}
		catch (const std::filesystem::filesystem_error& error) {
			LOG_ERROR << error.what();
			return false;
		}
		if (info == "")info = "\r\n";
		return true;
	}

	bool getSingleFileInfo(const std::string& filename, std::string& info, UserPermission permission)
	{
		// The FTP Time format can be:
		// 
		//     MMM DD hh:mm
		//   OR
		//     MMM DD  YYYY
		//   OR
		//     MMM DD YYYY
		//
		static const std::array<std::string, 12> month_names =
		{
			"Jan","Feb","Mar",
			"Apr","May","Jun",
			"Jul","Aug","Sep",
			"Oct","Nov","Dec"
		};
		std::stringstream stream;
		std::string fileType = std::filesystem::is_directory(filename) ? "d" : "-";
		std::string sPermission = "";
		if (fileType == "d") {
			std::string readable = static_cast<int>(permission & UserPermission::DirList) ? "r" : "-";
			std::string writeable = static_cast<int>(permission & UserPermission::DirCreate) ? "w" : "-";
			std::string enable = readable + writeable + "-";
			sPermission = fmt::format("{}{}{}", enable, enable, enable);
		}
		else {
			std::string readable = static_cast<int>(permission & UserPermission::FileRead) ? "r" : "-";
			std::string writeable = static_cast<int>(permission & UserPermission::FileWrite) ? "w" : "-";
			std::string enable = readable + writeable + "-";
			sPermission = fmt::format("{}{}{}", enable, enable, enable);
		}
		std::string name = std::filesystem::path(filename).filename().string();
		size_t fileSize = 0;
		if(std::filesystem::is_regular_file(filename)){
			fileSize = std::filesystem::file_size(filename);
		}
		// note: 获取上一次修改时间，我也不知道什么原理
		auto ftime = std::filesystem::last_write_time(filename);
		auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
			ftime - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
		std::time_t tt = std::chrono::system_clock::to_time_t(sctp);
		std::tm* ptm = std::localtime(&tt);

		// 组装一条info entry
		stream << fileType << sPermission << " " << "  1 ";
		stream << std::setw(10) << "jlftp" << " " << std::setw(10) << "jlftp" << " ";
		stream << std::setw(10) << fileSize << " ";
		stream << month_names[ptm->tm_mon] << " ";
		stream << std::setw(2) << ptm->tm_mday << " "
			<< std::setw(4) << ptm->tm_year + 1900 << " ";
		//<< std::setw(2) << std::setfill('0') << ptm->tm_sec << " "; // 不需要秒
		stream << name;

		info = stream.str();
		return true;
	}

	bool tryDelete(const std::string& filename)
	{
		try {
			std::filesystem::remove(filename);
		}
		catch (const std::filesystem::filesystem_error& error) {
			std::string errMsg = fmt::format("try to remove file failed. msg: {}", error.what());
			LOG_ERROR << errMsg;
			return false;
		}
		return true;
	}

	bool tryReName(const std::string& oldName, const std::string& newName)
	{
		try {
			std::filesystem::rename(oldName, newName);
		}
		catch (const std::filesystem::filesystem_error& e) {
			LOG_ERROR << "rename failed : " + std::string(e.what());
			return false;
		}
		return true;
	}

	bool checkFilenameLegal(const std::string& filename)
	{
		for (auto& c : filename) {
			if (c == '"' || c == ':' || c == '|' || c == '*' || c == '?' || c == '<' || c == '>' || c == '/' || c == '\\') {
				return false;
			}
		}
		return true;
	}
}